/*
 ============================================================================
 Name		: JsonObject.cpp
 Author	  : lin.chaoming
 Version	 : 0.1
 Copyright   : do1
 Description : CJsonObject implementation
 ============================================================================
 */

#include <eikenv.h>
#include <f32file.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "FileUtil.h"
#include "JsonObject.h"
#include "StringUtil.h"
#include "json_util.h"
#include "json_tokener.h"
#include "json_object_private.h"

CJsonObject::CJsonObject():data(NULL),size(0),refCount(0)
{
    obj=NULL;
}

CJsonObject::~CJsonObject()
{
}

json_type CJsonObject::GetType()
{
    return json_object_get_type(obj);
}

HBufC8* CJsonObject::ToString()
{
    const char* objString = json_object_to_json_string(obj);
    HBufC8 *result = CStringUtil::TransformCharToHBufC8(objString);
    return result;
}

void CJsonObject::SetObject( json_object *obj)
{
    this->obj = obj;
}

json_object* CJsonObject::GetObject()
{
    return this->obj;
}

CJsonObject* CJsonObject::NewObject()
{
    CJsonObject *jsonObj = new (ELeave) CJsonObject;
    json_object *obj = json_object_new_object();
    jsonObj->SetObject(obj);
    return jsonObj;
}

void CJsonObject::AddObject( const TDesC8& key, CJsonObject* jsonObj)
{
    const char *keyStr = CStringUtil::TransformTDes8ToConstChar(key);
    json_object_object_add(obj, keyStr, jsonObj->GetObject());
    delete[] keyStr;
}

CJsonObject* CJsonObject::GetObject( const TDesC8& key)
{
    const char *keyStr = CStringUtil::TransformTDes8ToConstChar(key);
    json_object *o = NULL;
    o = json_object_object_get(obj, keyStr);

    delete[] keyStr;
    CJsonObject *jsonObj = NULL;
    if (o != NULL)
    {
        jsonObj = new (ELeave) CJsonObject;
        jsonObj->SetObject(o);
        jsonObj->SetData(data,size);
    }
    return jsonObj;
}

void CJsonObject::DeleteObject( const TDesC8& key)
{
    if(obj)
    {
        const char *keyStr = CStringUtil::TransformTDes8ToConstChar(key);
        json_object_object_del(obj, keyStr);
        delete[] keyStr;
    }
}

CJsonObject* CJsonObject::NewArray()
{
    json_object *o = json_object_new_array();
    CJsonObject *jsonObj = new (ELeave) CJsonObject;
    jsonObj->SetObject(o);
    return jsonObj;
}

TInt CJsonObject::GetArrayLength()
{
    return json_object_array_length(obj);
}

void CJsonObject::AddArray( CJsonObject* jsonObj)
{
    json_object_array_add(obj, jsonObj->GetObject());
}

void CJsonObject::InsertArray( TInt index, CJsonObject* jsonObj)
{
    json_object_array_put_idx(obj, index, jsonObj->GetObject());
}

CJsonObject* CJsonObject::GetArrayById( TInt index)
{
    json_object *o = json_object_array_get_idx(obj, index);
    CJsonObject *jsonObj = new (ELeave) CJsonObject;
    if (o != NULL)
       {
           jsonObj->SetObject(o);
           jsonObj->SetData(data,size);
       }
    return jsonObj;
}

CJsonObject* CJsonObject::NewBooleanObject( TBool val)
{
    json_object *o = json_object_new_boolean(val);
    CJsonObject *jsonObj = new (ELeave) CJsonObject;
    jsonObj->SetObject(o);
    return jsonObj;
}
CJsonObject* CJsonObject::NewIntObject( TInt val)
{
    json_object *o = json_object_new_int(val);
    CJsonObject *jsonObj = new (ELeave) CJsonObject;
    jsonObj->SetObject(o);
    return jsonObj;
}
CJsonObject* CJsonObject::NewDoubleObject( double val)
{
    json_object *o = json_object_new_double(val);
    CJsonObject *jsonObj = new (ELeave) CJsonObject;
    jsonObj->SetObject(o);
    return jsonObj;
}
CJsonObject* CJsonObject::NewStringObject( const TDesC& val)
{
    const char* str = CStringUtil::TransformTDesToConstChar(val);
    json_object *o = json_object_new_string(str);
    CJsonObject *jsonObj = new (ELeave) CJsonObject;
    jsonObj->SetObject(o);
    delete[] str;
    str =  NULL;
    return jsonObj;
}
CJsonObject* CJsonObject::NewStringObject( const TDesC8& val)
{
    const char* str = CStringUtil::TransformTDes8ToConstChar(val);
    json_object *o = json_object_new_string(str);
    CJsonObject *jsonObj = new (ELeave) CJsonObject;
    jsonObj->SetObject(o);
    delete[] str;
    str =  NULL;
    return jsonObj;
}
TBool CJsonObject::GetBoolean()
{
    return json_object_get_boolean(obj);
}
TInt CJsonObject::GetInt()
{
    return json_object_get_int(obj);
}
double CJsonObject::GetDouble()
{
    return json_object_get_double(obj);
}
HBufC* CJsonObject::GetString()
{
    const char *str = json_object_get_string(obj);
    HBufC *result = CStringUtil::TransformCharToHBufC(str);
    return result;
}
HBufC* CJsonObject::GetStringFromGbk()
{
    HBufC *result = NULL;
    const char *str = json_object_get_string(obj);
    if (str)
    {
        HBufC8 *temp = CStringUtil::TransformCharToHBufC8(str);
        if (temp && temp->Length() > 0)
            result = CStringUtil::Gbk2UniL(*temp);
        delete temp;
        temp = NULL;
    }
    return result;
}
HBufC8* CJsonObject::GetString8()
{
    const char *str = json_object_get_string(obj);
    if(str)
    {
        HBufC8 *result = CStringUtil::TransformCharToHBufC8(str);
        return result;
    }
    return NULL;
}
HBufC8* CJsonObject::GetData()
{
    CJsonObject *offsetObj;
    CJsonObject *sizeObj;
    HBufC8 *returnData;
    returnData=NULL;
    offsetObj=NULL;
    sizeObj=NULL;
    TInt offSize;
    TInt dataSize;
    TPtrC8 returnBuf;
    unsigned char *pData;

    offsetObj = this->GetObject(_L8(JSON_OFFSET_STRING));
    if (!offsetObj)
    {
        goto clean;
    }
    sizeObj = this->GetObject(_L8(JSON_SIZE_STRING));
    if (!sizeObj)
    {
        goto clean;
    }
    offSize=offsetObj->GetInt();
    dataSize=sizeObj->GetInt();
    //returnData=HBufC8::NewL(dataSize);
        pData=this->data;
        pData+=offSize;
    returnBuf.Set(pData,dataSize);
    returnData=returnBuf.Alloc();

//    memcpy((void*)(returnData->Ptr()),(const void*)pData,dataSize);
clean:
    if(offsetObj)
    {
        delete offsetObj;
        offsetObj=NULL;
    }
    if(sizeObj)
    {
        delete sizeObj;
        sizeObj=NULL;
    }
    return returnData;
}
//CJsonObject* CJsonObject::NewObjectFromFile( const TDesC8& fileName)
//{
//    TBuf<50> buf;
//    buf.Copy(fileName);
//    HBufC8 *content=ReadFileL(buf);
//    const char *str = CStringUtil::TransformHBufToConstChar(content);
//    delete content;
//    content = NULL;
//    json_object *o = NULL;
//    o = json_tokener_parse(str);
//    delete[] str;
//    str=NULL;
//    CJsonObject *jsonObj = NULL;
//    if (o) 
//    {
//        jsonObj = new (ELeave) CJsonObject;
//        jsonObj->SetObject(o);
//    }
//    return jsonObj;
//}

CJsonObject* CJsonObject::NewObjectFromFile( const TDesC8& fileName)
{
    RBuf buf;
    buf.ReAllocL(fileName.Length());
    buf.Copy(fileName);
    HBufC8 *content=ReadFileL(buf);
    buf.Close();
    const char *str = CStringUtil::TransformHBufToConstChar(content);
    delete content;
    content = NULL;
    json_object *o = NULL;
    o = json_tokener_parse(str);
    delete[] str;
    str=NULL;
    CJsonObject *jsonObj = NULL;
    jsonObj = new (ELeave) CJsonObject;
    if (o) 
    {
        jsonObj->SetObject(o);
    }
    else
    {
        json_object* o=json_object_new_object();
        jsonObj->SetObject(o);
    }
    return jsonObj;
}

HBufC8* CJsonObject::ReadFileL( const TDesC& aFileName)
{
    RFs &rfs = CEikonEnv::Static()->FsSession();
     RFile file;
     User::LeaveIfError(file.Open(rfs, aFileName, EFileRead));
       CleanupClosePushL(file);
       TInt size;
       User::LeaveIfError(file.Size(size));
       HBufC8* buf = HBufC8::NewLC(size);
       TPtr8 bufPtr(buf->Des());
       User::LeaveIfError(file.Read(bufPtr));
       CleanupStack::Pop(); // buf
       CleanupStack::PopAndDestroy(1); // file, rfs
       return buf;
}
void CJsonObject::SerializationObjectToFile( const TDesC& fileName)
{
    HBufC8 *desString8 = ToString();
    RFs &rfs = CEikonEnv::Static()->FsSession();
    TBool isExist=CFileUtil::IsFileExists(rfs,fileName);
    RFile file;
    if(isExist)
    {
        rfs.Delete(fileName);
    }
    User::LeaveIfError(file.Create(rfs, fileName, EFileWrite));
    CleanupClosePushL(file);
    //TPtr8 buf=desString8->Des();
    file.Write(*desString8);
    file.Flush();
    //delete desString;
    delete desString8;
    CleanupStack::PopAndDestroy(1);
}

CJsonObject* CJsonObject::Parse( const TDesC8& aData)
{
    char *str = CStringUtil::TransformTDes8ToChar(aData);
    char *tempStr=str;
    json_object *o = NULL;
    char *jsonString;
    //unsigned char *data;
    int totalSize=aData.Length();
    //int jsonSize=0;
    //memcpy(&jsonSize,str,4);
    //tempStr+=4;
    //if (jsonSize > totalSize)
    //{
    //    tempStr -= 4;
    //    jsonSize = totalSize;
    //}
    //jsonString=CopyJsonString( tempStr, jsonSize);
    //tempStr+=jsonSize;
    //if(totalSize>jsonSize+4)
    //{
    //    data=(unsigned char*)CopyJsonString(tempStr,totalSize-4-jsonSize);
    //}
    jsonString=CopyJsonString( tempStr, totalSize);
    o = json_tokener_parse(jsonString);
    delete[] str;
    delete[] jsonString;
    CJsonObject *jsonObj = NULL;
    if (o)
    {
        jsonObj = new (ELeave) CJsonObject;
        jsonObj->SetObject(o);
//        if(totalSize>jsonSize+4)
//        {
//            jsonObj->SetData(data,totalSize-4-jsonSize);
//        }
    }
    return jsonObj;
}


void CJsonObject::SetData( unsigned char *data, int size)
{
    this->data=data;
    this->size=size;
}
char* CJsonObject::CopyJsonString( char *str, int size)
{
    char *jsonString;
    jsonString=(char*)malloc(size+1);
    memcpy(jsonString,str,size);
    jsonString[size]=0;
    return jsonString;
}
void CJsonObject::Destroy()
{
    if(obj)
    {
        json_object_put(obj);
    }
   
    if(refCount<=0)
    {
        if(data)
        {
            free(data);
            data=NULL;
        }
    }
    refCount--;
}

void CJsonObject::Clone()
{
    json_object_get(obj);
    refCount++;
}
